package org.pub.app.lunch;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

import org.pub.app.util.SortByCurrentLocation;
import org.pub.app.view.custom.RoundRectImageView;
import org.pub.lunch.google.map.view.SelectedRestaurantMap;
import org.pub.lunch.mashup.google.QueryAsync;
import org.pub.lunch.mashup.google.Restaurant;

import android.app.Activity;
import android.app.AlertDialog;
import android.app.AlertDialog.Builder;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.content.DialogInterface.OnMultiChoiceClickListener;
import android.content.Intent;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.location.Location;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.AdapterContextMenuInfo;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.BaseAdapter;
import android.widget.ListView;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;

/**
 * @author Austin Cho, Kyungseop Kim
 * 
 * 
 */
public class RestaurantList extends Activity {
	/**
	 * 리스트 뷰를 동적으로 생성
	 * 
	 * @author Administrator
	 * 
	 */
	boolean isActivated = false;
	boolean isSort = false;

	private SensorEventListener mySensorListener;

	private RelativeLayout progressLayout;

	private QueryAsync queryAsync;

	private ListView resultViewList;

	private int selectedPosition = -1;

	private SensorManager sensor;

	private static List<String> selectedCategoryList;

	/**
	 * 
	 */
	public RestaurantList() {
		super();
		items = new ArrayList<Restaurant>();
		categoriesList = new ArrayList<String>();
		selectedCategoryList = new ArrayList<String>();
	}

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.res_view);
		adapter = new ResultAdapter(this);
		
		currentLocation = (Location) getIntent().getExtras().getParcelable("MY CURRENT LOCATION");

		queryAsync = new QueryAsync(getBaseContext(), currentLocation, handler);
		new Thread(queryAsync).start();

		/*
		 * LocalAgent agent; try { agent = new LocalAgent(this,
		 * currentLocation); List<Restaurant> results = agent.getStepByStep();
		 * for (int i = 0; i < results.size(); i++) {
		 * 
		 * } } catch (Exception e) { e.printStackTrace(); }
		 */

		progressLayout = (RelativeLayout) findViewById(R.id.rlayout_progress);
		progressLayout.setVisibility(View.VISIBLE);

		resultViewList = (ListView) findViewById(R.id.result_list);
		resultViewList.setVisibility(View.GONE);
		resultViewList.setAdapter(adapter);
		
		resultViewList.setOnItemClickListener(new OnItemClickListener() {
			public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
				// 리스트의 아이템을 선택했을 때
				onListItemClick((ListView) parent, view, position, id);
			}
		});
		
		// setListAdapter(adapter);
		// 컨텍스트 메뉴 등록
		registerForContextMenu(resultViewList);

		// g-sensor
		sensor = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
		mySensorListener = new ShakeSensorEventListener();
		boolean accelSupported = sensor.registerListener(mySensorListener, sensor.getDefaultSensor(Sensor.TYPE_ACCELEROMETER), SensorManager.SENSOR_DELAY_UI);
		if (!accelSupported) {
			sensor.unregisterListener(mySensorListener);
		}
	}
	/**
	 * 업종별 정렬
	 */
	private void arrangeByCategory() {
		// Collections.sort(items);
		if (selectedCategoryList.size() > 0) {
			Collections.sort(selectedCategoryList);
			Log.i(TAG, selectedCategoryList.size() + " Select Category Size.");
			List<Restaurant> sortList = new ArrayList<Restaurant>();
			for (Restaurant r : items) {
				if (r.getCategories() != null && r.getCategories().size() > 0) {
					// 카테고리가 있는 경우
					String compareStr = r.getCategories().get(0);
					if (selectedCategoryList.contains(compareStr)) {
						sortList.add(0, r);
					} else {
						sortList.add(sortList.size(), r);
					}
				} else {
					// 카테고리가 없는 경우
					sortList.add(sortList.size(), r);
				}
			}
			Log.i(TAG, items.toString());
			items = sortList;
			Log.i(TAG, items.toString());

			// Collections.sort(items, new
			// SortByCategory(selectedCategoryList));
			adapter.notifyDataSetChanged();
		}
	}

	/**
	 * 현재 위치를 기준으로 거리순으로 리스트를 정렬한다.
	 */
	private void arrangeByDistance() {
		if (currentLocation == null) {
			currentLocation = (Location) getIntent().getExtras().getParcelable("MY CURRENT LOCATION");
		}
		Collections.sort(items, new SortByCurrentLocation(currentLocation));
		Log.i("Res_List is sorted by distance, " + items.size(), Arrays.toString(items.toArray()));
		adapter.notifyDataSetChanged();
	}

	private void callRestaurant(String phoneNumber) {
		if (phoneNumber == null || phoneNumber.equals("")) {
			Toast.makeText(this.getBaseContext(), R.string.no_phone, 5).show();
		} else {
			phoneNumber = "tel:" + phoneNumber.replace("-", "");
			Intent dialIntent = new Intent(Intent.ACTION_DIAL, Uri.parse(phoneNumber));
			startActivity(dialIntent);
		}
	}

	private void makeCategoryList() {
		// 업종별 정렬에 필요한 카테고리를 보여준다.
		showDialog(DIALOG_CATEGORY);
	}

	/**
	 * 1. call restaurant 2. select position on map
	 * 
	 * @param menu
	 */
	private void makeMenu(Menu menu) {
		// 컨택스트 메뉴 생성
		menu.add(Menu.NONE, MENU_CALL_RESTAURANT, Menu.NONE, R.string.menu_one);
		menu.add(Menu.NONE, MENU_SHOWMAP, Menu.NONE, R.string.menu_two);
		menu.add(Menu.NONE, MENU_SORT_DISTANCE, Menu.NONE, R.string.menu_three);
		menu.add(Menu.NONE, MENU_SORT_CATEGORY, Menu.NONE, R.string.menu_four);
	}

	@Override
	public boolean onContextItemSelected(MenuItem item) {
		return this.whichItemSelected(item) || super.onContextItemSelected(item);
	}


	@Override
	public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
		// 리스트를 길게 누르면 컨텍스트 메뉴를 생성한다.
		selectedPosition = ((AdapterContextMenuInfo) menuInfo).position;
		makeMenu(menu);
	}

	protected Dialog onCreateDialog(int id) {
		Log.i(TAG, "CALL DIALOG :" + id);
		Builder builder = new AlertDialog.Builder(this);
		switch (id) {
		case DIALOG_INTERNET_ERROR:
			builder.setIcon(R.drawable.internet_connect_error);
			builder.setTitle(R.string.title_internet_error).setMessage(R.string.INTERNET_ERROR).setNeutralButton(R.string.dialogOKButton, new DialogInterface.OnClickListener() {

				public void onClick(DialogInterface dialog, int which) {
					// 창이 닫힘
					if (items.size() > 0) {
						showResultList();
					} else {
						finish();
					}
				}
			});

			break;
		case DIALOG_NODATA:
			builder.setIcon(R.drawable.nodata);
			builder.setTitle(R.string.nodata).setMessage(R.string.restaurant_no_data).setNeutralButton(R.string.dialogOKButton, new DialogInterface.OnClickListener() {

				public void onClick(DialogInterface dialoginterface, int i) {
					if (items.size() > 0) {
						showResultList();
					} else {
						finish();
					}
				}
			});
			break;
		case DIALOG_CATEGORY:
			Collections.sort(categoriesList);
			// selectedCategoryList.clear();
			builder.setTitle(R.string.title_categoryDialog);
			builder.setMultiChoiceItems(categoriesList.toArray(new String[categoriesList.size()]), null, new OnMultiChoiceClickListener() {

				public void onClick(DialogInterface dialog, int position, boolean isCheck) {
					// 다이얼로그에서 리스트 아이템을 선택하는 경우
					if (isCheck) {
						selectedCategoryList.add(categoriesList.get(position));
						Log.i(TAG, categoriesList.size() + " " + selectedCategoryList.size() + " select && Size");
					} else {
						if (selectedCategoryList.contains(categoriesList.get(position))) {
							selectedCategoryList.remove(categoriesList.get(position));
						}
						Log.i(TAG, categoriesList.size() + " " + selectedCategoryList.size() + " Unselect && Size");
					}

				}

			});

			builder.setNeutralButton(R.string.dialogOKButton, new OnClickListener() {

				public void onClick(DialogInterface dialog, int which) {
					// 다이얼로그 OK버튼을 눌렀을 경우
					if (selectedCategoryList.size() > 0)
						arrangeByCategory();
				}
			});
			break;
		}
		return builder.create();
	}

	public boolean onCreateOptionsMenu(Menu menu) {
		makeMenu(menu);
		return super.onCreateOptionsMenu(menu);
	}

	protected void onListItemClick(ListView l, View v, int position, long id) {
		selectedPosition = position;
		Restaurant currentItem = items.get(position);

		String phoneNum = currentItem.getPhone();
		String addr = currentItem.getAddress();
		String name = currentItem.getName();
		List<String> categories = currentItem.getCategories();
		String categoryName = null;
		if (categories.size() > 0) {
			categoryName = categories.get(0);
		}

		StringBuffer detail = new StringBuffer();

		if (addr != null && !addr.equals("")) {
			detail.append(addr);
			Toast.makeText(this.getBaseContext(), detail.toString(), Toast.LENGTH_SHORT).show();
		}

		// //add austin test code
		// Intent in = new Intent( getBaseContext() ,
		// AnimationTestActivity.class );
		// startActivity( in );

		StringBuffer itemDetail = new StringBuffer();
		itemDetail.append(name + " " + phoneNum + " " + categoryName);

		Log.i(TAG, itemDetail.toString() + " Item Detail");
		Log.i(TAG, String.valueOf(currentLocation.distanceTo(items.get(position).getLocation())) + " Between current and selecting item");
		Log.i(TAG, "All Category & size: " + categoriesList.size() + Arrays.toString(categoriesList.toArray()));
	}

	@Override
	public boolean onOptionsItemSelected(MenuItem item) {

		return this.whichItemSelected(item) || super.onOptionsItemSelected(item);
	}

	protected void onPause() {
		if (sensor != null) {
			sensor.unregisterListener(mySensorListener);
			sensor = null;
		}
		super.onPause();
	}

	protected void onResume() {
		super.onResume();
		sensor = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
		mySensorListener = new ShakeSensorEventListener();
		boolean accelSupported = sensor.registerListener(mySensorListener, sensor.getDefaultSensor(Sensor.TYPE_ACCELEROMETER), SensorManager.SENSOR_DELAY_UI);
		if (!accelSupported) {
			sensor.unregisterListener(mySensorListener);
			sensor = null;
		}
		isShake = false;
	}

	@Override
	protected void onStart() {
		super.onStart();
	}

	protected void onStop() {
		super.onStop();
		queryAsync.setAlive(false);
	}

	/**
	 * 해당 식당을 지도에 표시
	 * 
	 * @param restaurant
	 *            컨텍스트 메뉴를 호출한 식당
	 */
	private void showMap(Restaurant restaurant) throws Exception {
		if (restaurant == null) {
			restaurant = items.get(selectedPosition);
		}
		String name = restaurant.getName();
		SelectedRestaurantMap mapActivity = new SelectedRestaurantMap();
		Intent mapIntent = new Intent(this.getBaseContext(), mapActivity.getClass());
		mapIntent.putExtra("RESTAURANT", new Location(restaurant.getLocation()));
		mapIntent.putExtra("RESTAURANT_NAME", new String(name));
		mapIntent.putExtra("CURRENT", currentLocation);
		startActivity(mapIntent);
	}

	private void showResultList() {
		// remove Austin 2010-04-17
		// AnimationSet set = new AnimationSet(true);
		//
		// Animation animation = new AlphaAnimation(0.0f, 1.0f);
		// animation.setDuration(500);
		// set.addAnimation(animation);
		//
		// animation = new TranslateAnimation(Animation.RELATIVE_TO_SELF, 0.0f,
		// Animation.RELATIVE_TO_SELF, 0.0f, Animation.RELATIVE_TO_SELF, -1.0f,
		// Animation.RELATIVE_TO_SELF, 0.0f);
		// animation.setDuration(200);
		// set.addAnimation(animation);
		//
		// LayoutAnimationController controller = new
		// LayoutAnimationController(set, 0.5f);

		// resultList.setLayoutAnimation(controller);
		progressLayout.setVisibility(View.GONE);
		resultViewList.setVisibility(View.VISIBLE);

		isActivated = true;
	}

	/**
	 * 어떤 메뉴를 선택했는지 반환
	 * 
	 * @param selectItem
	 * @return
	 */
	private boolean whichItemSelected(MenuItem selectItem) {
		// 컨텍스트 메뉴를 호출하기전 어떤 리스트 아이템에서 선택했는지 정보를 가져옴.
		AdapterContextMenuInfo menuInfo = (AdapterContextMenuInfo) selectItem.getMenuInfo();
		Restaurant selectedRestaurant = null;
		try {
			if (menuInfo != null)
				selectedRestaurant = items.get(menuInfo.position);
			switch (selectItem.getItemId()) {
			case MENU_CALL_RESTAURANT:
				if (selectedPosition == -1) {
					Toast.makeText(this.getBaseContext(), R.string.select_restaurant, 10).show();
				} else {
					String phone = null;
					if (selectedPosition != -1) {
						phone = items.get(selectedPosition).getPhone();
					} else {
						phone = selectedRestaurant.getPhone();
					}
					callRestaurant(phone);
				}
				return true;
			case MENU_SHOWMAP:
				if (selectedPosition == -1) {
					Toast.makeText(this.getBaseContext(), R.string.select_restaurant, 10).show();
				} else {
					showMap(selectedRestaurant);
				}
				return true;
			case MENU_SORT_DISTANCE:
				arrangeByDistance();
				return true;
			case MENU_SORT_CATEGORY:
				// 업종별 정렬
				makeCategoryList();
				// arrangeByCategory();
				return true;
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return false;
	}
	
	class ResultAdapter extends BaseAdapter {

		Context context;

		public ResultAdapter(Context context) {
			super();
			this.context = context;
		}

		public int getCount() {
			// 리스트의 갯수
			return items.size();
		}

		public Restaurant getItem(int position) {
			// 해당 위치의 리스트 아이템
			return items.get(position);
		}

		public long getItemId(int position) {
			// 해당 위치의 리스트 아이템의 id
			return position;
		}

		public View getView(int position, View v, ViewGroup parent) {
			if (v == null) {
				LayoutInflater vi = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
				v = vi.inflate(R.layout.ret_info, null);
			}
			RoundRectImageView res_image = (RoundRectImageView) v.findViewById(R.id.ImageView01);
			res_image.setRoundThickness(6);
			res_image.setHeight(80);
			res_image.setWidth(80);
			TextView name = (TextView) v.findViewById(R.id.TextView01);
			TextView category = (TextView) v.findViewById(R.id.TextView_Category);
			TextView phone = (TextView) v.findViewById(R.id.TextView_Phone);
			Restaurant restaurant = items.get(position);
			name.setText(restaurant.getName().trim());

			List<String> categories = restaurant.getCategories();
			String categoryName = null;
			if (categories.size() > 0) {
				categoryName = categories.get(0);
				category.setText(categoryName.trim());
			} else {
				category.setText(R.string.no_category);
			}

			phone.setText(restaurant.getPhone().trim().split(",", 1)[0]);
			// res_image.setImageDrawable(restaurant.getDrawable());
			res_image.setBackgroundDrawable(restaurant.getDrawable());

			return v;
		}

	}

	boolean isShake = false;

	private class ShakeSensorEventListener implements SensorEventListener {

		static final int SHAKE_THRESHOLD = 1000;
		float last_x, last_y, last_z;
		long lastUpdate = -1;
		float x, y, z;

		public void onAccuracyChanged(Sensor sensor, int accuracy) {

		}

		public void onSensorChanged(SensorEvent event) {
			synchronized (this) {
				Sensor sensor = event.sensor;
				if (sensor.getType() == Sensor.TYPE_ACCELEROMETER) {

					long curTime = System.currentTimeMillis();

					if ((curTime - lastUpdate) > 100) {
						long diffTime = curTime - lastUpdate;
						lastUpdate = curTime;
						float[] value = event.values;
						x = Math.abs(value[SensorManager.DATA_X]);
						y = Math.abs(value[SensorManager.DATA_Y]);
						z = Math.abs(value[SensorManager.DATA_Z]);

						float speed = Math.abs((x + y + z) - (last_x + last_y + last_z)) / diffTime * 10000;

						if (speed > SHAKE_THRESHOLD && !isShake) {
							// 에니 호출...
							isShake = true;
							Intent in = new Intent(getBaseContext(), AnimationTestActivity.class);
							startActivity(in);

							// Toast.makeText(getBaseContext(), "Shaked !!!! " +
							// speed, Toast.LENGTH_SHORT).show();
						}
						last_x = x;
						last_y = y;
						last_z = z;
					}
				}
			}

		}

	}

	private static final String TAG = "RestaurantList";

	public static List<Restaurant> items;

	/**
	 * 컨텍스트 메뉴1 아이디
	 */
	private static final int MENU_CALL_RESTAURANT = Menu.FIRST;

	/**
	 * 컨텍스트 메뉴2 아이디
	 */
	private static final int MENU_SHOWMAP = Menu.FIRST + 1;
	/**
	 * 컨텍스트 메뉴4 아이디
	 */
	private static final int MENU_SORT_CATEGORY = Menu.FIRST + 3;

	/**
	 * 컨텍스트 메뉴3 아이디
	 */
	private static final int MENU_SORT_DISTANCE = Menu.FIRST + 2;

	private static final int DIALOG_INTERNET_ERROR = 100;
	private static final int DIALOG_NODATA = 200;
	private static final int DIALOG_CATEGORY = 300;

	private ResultAdapter adapter;
	private static List<String> categoriesList;

	public static Location currentLocation;
	private Handler handler = new Handler() {
		public void handleMessage(Message msg) {

			switch (msg.what) {
			case QueryAsync.RESTAURANT_DATA:
				if (!isActivated && items.size() > 5) {
					showResultList();
				}
				Restaurant item = (Restaurant) (msg.obj);
				items.add(item);
				int size = item.getCategories().size();

				if (size > 0) {
					String categoryName = item.getCategories().get(0);
					if (!categoriesList.contains(categoryName)) {
						categoriesList.add(categoryName);
					}
				}
				adapter.notifyDataSetChanged();
				break;
			case QueryAsync.QUERYASYNC_ERROR:
				// showResultList();
				showDialog(DIALOG_INTERNET_ERROR);
				Exception e = (Exception) msg.obj;
				Log.w(TAG, e);
				// Toast.makeText(getBaseContext(), R.string.INTERNET_ERROR,
				// Toast.LENGTH_LONG).show();
				break;
			case QueryAsync.QUERYASYNC_NODATA:
				// showResultList();
				showDialog(DIALOG_NODATA);
				Exception e1 = (Exception) msg.obj;
				Log.w(TAG, e1);
				// Toast.makeText(getBaseContext(),R.string.restaurant_no_data ,
				// Toast.LENGTH_LONG).show();
			}
		}

	};
	

}
